package adaptive.opencom;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import OpenCOM.IConnections;
import OpenCOM.ILifeCycle;
import OpenCOM.IMetaInterface;
import OpenCOM.IUnknown;
import adaptive.ime.MyKeyboardService.KeyboardSize;
import adaptive.opencom.AdaptationRequest.AdaptationType;
import adaptive.opencom.log.KeyLog;
import android.annotation.SuppressLint;
import android.util.Log;

public class ThreeErrorProximityKeyboardPolicyComponent extends AbstractKeyboardPolicyComponent
	implements IAdaptationPolicy, IUnknown, ILifeCycle, IMetaInterface, IConnections {

	private Map<Character, List<Character>> proximityMap;
	
	public ThreeErrorProximityKeyboardPolicyComponent(IUnknown mpIOCM) {
		super(mpIOCM);
		
		initProximityMap();
	}
	
	public void initProximityMap() {
		proximityMap = new HashMap<Character, List<Character>>();
		
		proximityMap.put('q', Arrays.asList(new Character[]{'w', 'a'}));
		proximityMap.put('w', Arrays.asList(new Character[]{'q', 'e', 'a', 's'}));
		proximityMap.put('e', Arrays.asList(new Character[]{'w', 'r', 's', 'd'}));
		proximityMap.put('r', Arrays.asList(new Character[]{'e', 't', 'd', 'f'}));
		proximityMap.put('t', Arrays.asList(new Character[]{'r', 'y', 'f', 'g'}));
		proximityMap.put('y', Arrays.asList(new Character[]{'t', 'u', 'g', 'h'}));
		proximityMap.put('u', Arrays.asList(new Character[]{'y', 'i', 'h', 'j'}));
		proximityMap.put('i', Arrays.asList(new Character[]{'u', 'o', 'j', 'k'}));
		proximityMap.put('o', Arrays.asList(new Character[]{'i', 'p', 'k', 'l'}));
		proximityMap.put('p', Arrays.asList(new Character[]{'o', 'l'}));
		
		proximityMap.put('a', Arrays.asList(new Character[]{'q', 'w', 's', 'z'}));
		proximityMap.put('s', Arrays.asList(new Character[]{'w', 'e', 'a', 'd', 'z', 'x'}));
		proximityMap.put('d', Arrays.asList(new Character[]{'e', 'r', 's', 'f', 'z', 'x', 'c'}));
		proximityMap.put('f', Arrays.asList(new Character[]{'r', 't', 'd', 'g', 'x', 'c', 'v'}));
		proximityMap.put('g', Arrays.asList(new Character[]{'t', 'y', 'f', 'h', 'c', 'v', 'b'}));
		proximityMap.put('h', Arrays.asList(new Character[]{'y', 'u', 'g', 'j', 'v', 'b', 'n'}));
		proximityMap.put('j', Arrays.asList(new Character[]{'u', 'i', 'h', 'k', 'b', 'n', 'm'}));
		proximityMap.put('k', Arrays.asList(new Character[]{'i', 'o', 'j', 'l', 'n', 'm'}));
		proximityMap.put('l', Arrays.asList(new Character[]{'o', 'p', 'k', 'm'}));
		
		proximityMap.put('z', Arrays.asList(new Character[]{'x', 'a', 's', 'd'}));
		proximityMap.put('x', Arrays.asList(new Character[]{'z', 'c', 's', 'd', 'f'}));
		proximityMap.put('c', Arrays.asList(new Character[]{'x', 'v', 'd', 'f', 'g'}));
		proximityMap.put('v', Arrays.asList(new Character[]{'c', 'b', 'f', 'g', 'h'}));
		proximityMap.put('b', Arrays.asList(new Character[]{'v', 'n', 'g', 'h', 'j'}));
		proximityMap.put('n', Arrays.asList(new Character[]{'b', 'm', 'h', 'j', 'k'}));
		proximityMap.put('m', Arrays.asList(new Character[]{'n', 'j', 'k', 'l'}));
		/*
		for(Entry<Character, List<Character>> entry : proximityMap.entrySet()) {
			StringBuilder builder = new StringBuilder();
			for(Character c : entry.getValue())
				builder.append(c).append(" , ");
			Log.d(entry.getKey().toString(), builder.toString());
		}*/
	}

	// ILifeCycle operations
	@Override
	public boolean startup(Object data) {
		return true;
	}

	@Override
	public boolean shutdown() {
		return true;
	}

	// IAdaptationPolicy Operations
	@SuppressLint("DefaultLocale")
	@Override
	public AdaptationRequest adaptationRequest() {
		//Log.d("AdaptationRequest", "Proximity");
		int errorCount = 0;
		
		char lastKey = '\0';
		int error = 0;
		
		for(KeyLog keyLog : rcEventMonitor.m_pIntf.getKeyboardLog()) {
			//Log.d("KeyLog", String.valueOf(keyLog.getKeyCode()));
			if(keyLog.getKeyCode() == -5) {
				error = 1;
			} else {
				//Log.d("back", String.valueOf(error));
				if(error == 1) {
					if(lastKey != '\0') {
						StringBuilder builder = new StringBuilder();
						for(Character c : proximityMap.get(lastKey))
							builder.append(c).append(" , ");
						//Log.d(String.valueOf(lastKey), builder.toString());
						
						char currentKey = String.valueOf((char) keyLog.getKeyCode()).toLowerCase().charAt(0);
					
						if(proximityMap.get(lastKey).contains(currentKey)) {
							//Log.d("PROX", lastKey + " , " + (char) keyLog.getKeyCode());
							error = 0;
							errorCount++;
							//Log.d("Error", String.valueOf(errorCount));
							if(errorCount == 3)
								break;
						}
						//Log.d("SEQ", lastKey + " , " + (char) keyLog.getKeyCode());
					}
				}
				lastKey = String.valueOf((char) keyLog.getKeyCode()).toLowerCase().charAt(0);
			}
		}
		
		// Check for adaptation request
		if(errorCount == 3) {
			Log.d("Required", "ThreeErrorProximity");
			rcEventMonitor.m_pIntf.getKeyboardLog().clear();
			
			// Choose a Larger keyboard
			KeyboardSize newSize;
			switch(mSize) {
				case SMALL:
					newSize = KeyboardSize.MEDIUM;
					break;
				case MEDIUM:
					newSize = KeyboardSize.LARGE;
					break;
				case LARGE:
					newSize = KeyboardSize.SMALL;
					break;
				default:
					newSize = KeyboardSize.LARGE;
			}
			mSize = newSize;
			return new AdaptationRequest(AdaptationType.KEYBOARD_SIZE, newSize);
		} else 
			return new AdaptationRequest();
	}
}
